package com.coffee.job.service.quartz.impl;

import com.coffee.job.api.quartz.api.QuartzJobService;
import com.coffee.job.api.quartz.entity.TaskDefine;
import com.google.common.collect.Maps;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.Service;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.reflections.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 核心其实就是Scheduler的功能,这里只是非常简单的示例说明其功能
 * 如需根据自身业务进行扩展请参考{@link Scheduler}
 *
 * @author Xulg
 * Created in 2019-08-05 8:31
 */
@DubboService(dynamic = true)
public class QuartzJobServiceImpl implements QuartzJobService {
    private static final Logger logger = LoggerFactory.getLogger(QuartzJobServiceImpl.class);

    /**
     * Quartz定时任务核心的功能实现类
     */
    @SuppressWarnings("SpringJavaAutowiredMembersInspection")
    @Autowired
    private Scheduler scheduler;

    /**
     * 创建和启动 定时任务
     * {@link Scheduler#scheduleJob(JobDetail, Trigger)}
     *
     * @param define 定时任务
     */
    @Override
    public Void addScheduleJob(TaskDefine define) {
        //1.定时任务 的 名字和组名
        JobKey jobKey = define.getJobKey();
        //2.定时任务 的 元数据
        JobDataMap jobDataMap = this.getJobDataMap(define.getJobDataMap());
        //3.定时任务 的 描述
        String description = define.getDescription();
        //4.定时任务 的 逻辑实现类
        Class<? extends Job> jobClass = define.getJobClass();
        //5.定时任务 的 cron表达式
        String cron = define.getCronExpression();
        JobDetail jobDetail = this.getJobDetail(jobKey, description, jobDataMap, jobClass);
        Trigger trigger = this.getTrigger(jobKey, description, jobDataMap, cron);
        try {
            if (!scheduler.checkExists(jobKey)) {
                scheduler.scheduleJob(jobDetail, trigger);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return null;
    }

    @Override
    public Void addScheduleJob(String name, String group, String cronExpression, String jobClassName, String description) {
        TaskDefine taskdefine = new TaskDefine(name, group);
        taskdefine.setJobClassName(jobClassName);
        taskdefine.setDescription(description);
        taskdefine.setCronExpression(cronExpression);
        taskdefine.setJobDataMap(Maps.newHashMapWithExpectedSize(0));
        Class<?> job = ReflectionUtils.forName(jobClassName);
        taskdefine.setJobClass((Class<? extends Job>) job);
        return addScheduleJob(taskdefine);
    }

    /**
     * 暂停Job
     * {@link Scheduler#pauseJob(JobKey)}
     */
    @Override
    public Void pauseJob(JobKey jobKey) {
        try {
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 恢复Job
     * {@link Scheduler#resumeJob(JobKey)}
     */
    @Override
    public Void resumeJob(JobKey jobKey) {
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 删除Job
     * {@link Scheduler#deleteJob(JobKey)}
     */
    @Override
    public Void deleteJob(JobKey jobKey) {
        try {
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return null;
    }

    @Override
    public boolean modifyJobCron(String name, String group, String cronExpression) {
        // 如果cron表达式的格式不正确,则返回修改失败
        if (!CronExpression.isValidExpression(cronExpression)) {
            return false;
        }
        TriggerKey triggerKey = new TriggerKey(name, group);
        try {
            if (!scheduler.checkExists(triggerKey)) {
                return false;
            }
            CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // 如果cron发生变化了,则按新cron触发 进行重新启动定时任务
            if (!cronTrigger.getCronExpression().equalsIgnoreCase(cronExpression)) {
                CronTrigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity(triggerKey)
                        .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                        .usingJobData(cronTrigger.getJobDataMap())
                        .build();
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
            logger.error("修改Job的cron表达式错误", e);
            return false;
        }
        return true;
    }

    @Override
    public List<TaskDefine> queryAllJob() {
        List<TaskDefine> result = new ArrayList<>();
        try {
            Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.anyGroup());
            for (JobKey jobKey : jobKeys) {
                JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                // 封装job信息
                TaskDefine taskDefine = new TaskDefine(jobKey.getName(), jobKey.getGroup());
                taskDefine.setDescription(jobDetail.getDescription());
                taskDefine.setJobDataMap(jobDetail.getJobDataMap());
                taskDefine.setJobClass(jobDetail.getJobClass());
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    if (trigger instanceof CronTrigger) {
                        taskDefine.setCronExpression(((CronTrigger) trigger).getCronExpression());
                        break;
                    }
                }
                result.add(taskDefine);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return result;
    }

    @Override
    public List<TaskDefine> queryAllCurrentRunningJob() {
        List<TaskDefine> result = new ArrayList<>();
        try {
            List<JobExecutionContext> currentlyExecutingJobs = scheduler.getCurrentlyExecutingJobs();
            for (JobExecutionContext jobExecutionContext : currentlyExecutingJobs) {
                JobDetail jobDetail = jobExecutionContext.getJobDetail();
                JobKey jobKey = jobDetail.getKey();
                Trigger trigger = jobExecutionContext.getTrigger();
                // 封装job信息
                TaskDefine taskDefine = new TaskDefine(jobKey.getName(), jobKey.getGroup());
                taskDefine.setDescription(jobDetail.getDescription());
                taskDefine.setJobDataMap(jobDetail.getJobDataMap());
                taskDefine.setJobClass(jobDetail.getJobClass());
                if (trigger instanceof CronTrigger) {
                    taskDefine.setCronExpression(((CronTrigger) trigger).getCronExpression());
                }
                result.add(taskDefine);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return result;
    }
}
